package com.yilin.platform.service.impl.data;


import com.baidu.aip.ocr.AipOcr;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.yilin.platform.base_core.commons.exception.BusinessException;
import com.yilin.platform.base_core.commons.utils.CommonUtil;
import com.yilin.platform.base_core.commons.utils.DateTimeUtil;
import com.yilin.platform.base_core.commons.utils.StringUtil;
import com.yilin.platform.entity.system.TruckEnergyType;
import com.yilin.platform.entity.system.TruckPlate;
import com.yilin.platform.entity.user.Account;
import com.yilin.platform.service.data.IBaiDuOcrService;
import com.yilin.platform.service.impl.system.ParamService;
import com.yilin.platform.service.impl.user.AccountService;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

@Service
@Transactional
public class BaiDuOcrService implements IBaiDuOcrService {
    @Value("${baidu-ocr.app-id}")
    private String appId;
    @Value("${baidu-ocr.app-key}")
    private String appKey;
    @Value("${baidu-ocr.secret-key}")
    private String secretKey;
    @Resource
    ParamService paramService;
    @Resource
    AccountService accountService;

    /**
     * 证件正反面
     */
    public enum Side {
        front(0, "正面"),
        back(1, "反面");

        @EnumValue
        public Integer index;
        public String name;

        Side(Integer index, String name) {
            this.index = index;
            this.name = name;
        }
    }

    private AipOcr getAipOcr() {
        AipOcr client = new AipOcr(appId,appKey, secretKey);
        client.setConnectionTimeoutInMillis(2000);
        client.setSocketTimeoutInMillis(60000);
        return client;
    }

    private HashMap<String, String> getAipOpt() {
        HashMap<String, String> options = new HashMap<>();
        options.put("detect_direction", "true");
        options.put("detect_risk", "false");
        return options;
    }

    //银行卡
    @Override
    public Map<String, Object> ocrBankCard(Account loginUser, String imagePath) {
        JSONObject res = getAipOcr().bankcard(imagePath, getAipOpt());
        Map<String, Object> map = new HashMap<>();
        JSONObject result = res.getJSONObject("result");
        if (result.has("bank_card_number")) {
            map.put("bankCardNo", StringUtil.trimStr(result.getString("bank_card_number")));
        }
        if (result.has("bank_name")) {
            map.put("bankName", StringUtil.trimStr(result.getString("bank_name")));
        }
        return map;
    }

    //身份证识别
    @Override
    public Map<String, Object> ocrIdCard(Account loginUser, String imagePath, Side side) {
        if (side == null) {
            side = Side.front;//front：身份证含照片的一面；back：身份证带国徽的一面
        }
        JSONObject res = getAipOcr().idcard(imagePath, side.name(), getAipOpt());
        if (!res.has("words_result")) throw new BusinessException("身份证OCR识别失败,请手动填写证件信息!");
        Map<String, Object> map = new HashMap<>();
        JSONObject result = res.getJSONObject("words_result");
        if (result.has("姓名")) {
            map.put("name", result.getJSONObject("姓名").getString("words"));
        }
        if (result.has("出生")) {
            String string = result.getJSONObject("出生").getString("words");
            map.put("birthday", DateTimeUtil.dateToString(DateTimeUtil.stringToDate(string, "yyyyMMdd")));
        }
        if (result.has("公民身份号码")) {
            map.put("idCardNo", result.getJSONObject("公民身份号码").getString("words"));
        }
        if (result.has("住址")) {
            map.put("address", result.getJSONObject("住址").getString("words"));
        }
        if (result.has("签发日期")) {
            String string = result.getJSONObject("签发日期").getString("words");
            map.put("startDate", DateTimeUtil.dateToString(DateTimeUtil.stringToDate(string, "yyyyMMdd")));
        }
        if (result.has("失效日期")) {
            String string = result.getJSONObject("失效日期").getString("words");
            map.put("endDate", DateTimeUtil.dateToString(DateTimeUtil.stringToDate(string, "yyyyMMdd")));
        }
        return map;
    }

    //营业执照识别
    @Override
    public Map<String, Object> ocrBusinessLicense(Account loginUser, String imagePath) {
        JSONObject res = getAipOcr().businessLicense(imagePath, getAipOpt());
        if (!res.has("words_result")) throw new BusinessException("营业执照OCR识别失败,请手动填写证件信息!");
        Map<String, Object> map = new HashMap<>();
        JSONObject result = res.getJSONObject("words_result");
        if (result.has("单位名称")) {
            map.put("name", result.getJSONObject("单位名称").getString("words"));
        }
        if (result.has("证件编号")) {
            map.put("businessNo", result.getJSONObject("证件编号").getString("words"));
        }
        if (result.has("社会信用代码")) {//
            map.put("businessNo", result.getJSONObject("社会信用代码").getString("words"));
        }
        if (result.has("地址")) {
            map.put("companyAddress", result.getJSONObject("地址").getString("words"));
        }
        if (result.has("法人")) {
            map.put("businessName", result.getJSONObject("法人").getString("words"));
        }
        if (result.has("有效期")) {
            String endDate = result.getJSONObject("有效期").getString("words");
            if (endDate.contains("年")) endDate = endDate.replace("年", "-");
            if (endDate.contains("月")) endDate = endDate.replace("月", "-");
            if (endDate.contains("日")) endDate = endDate.replace("日", "");
            map.put("validityDate", endDate);
        }
        return map;
    }

    //驾驶证
    @Override
    public Map<String, Object> ocrDrivingLicenseAuth(Account loginUser, String imagePath) {
        JSONObject res = getAipOcr().drivingLicense(imagePath, getAipOpt());
        if (!res.has("words_result")) throw new BusinessException("驾驶证OCR识别失败,请手动填写证件信息!");
        Map<String, Object> map = new HashMap<>();
        JSONObject result = res.getJSONObject("words_result");
        if (result.has("姓名")) {
            map.put("drivingLicenseName", result.getJSONObject("姓名").getString("words"));
        }
        if (result.has("证号")) {
            map.put("drivingLicenseNo", result.getJSONObject("证号").getString("words"));
        }
        if (result.has("住址")) {//
            map.put("drivingLicenseAddress", result.getJSONObject("住址").getString("words"));
        }
        if (result.has("发证单位")) {
            map.put("issuingOrganizations", result.getJSONObject("发证单位").getString("words"));
        }
        if (result.has("准驾车型")) {
            map.put("drivingLicenseType", result.getJSONObject("准驾车型").getString("words"));
        }
        if (result.has("有效期限")) {//20200708
            String endDate = result.getJSONObject("有效期限").getString("words");
            String year = endDate.substring(0, 4);
            String month = endDate.substring(4, 6);
            String day = endDate.substring(6, 8);
            map.put("validityStartDate", year + "-" + month + "-" + day);
        }
        if (result.has("至")) {//20200708
            String endDate = result.getJSONObject("至").getString("words");
            String year = endDate.substring(0, 4);
            String month = endDate.substring(4, 6);
            String day = endDate.substring(6, 8);
            map.put("validityEndDate", year + "-" + month + "-" + day);
        }
        return map;
    }

    //道路运输从业资格证 【0e9b63c67731bed661bb83ecdc427e1d】
    @Override
    public Map<String, Object> ocrQualificationCert(Account loginUser, String imagePath) {
        HashMap<String, String> options = new HashMap<>();
        options.put("templateSign", "0e9b63c67731bed661bb83ecdc427e1d");
        JSONObject res = getAipOcr().custom(imagePath, options);
        Map<String, Object> map = new HashMap<>();
        if (!res.has("data") || !res.getJSONObject("data").has("ret")) {
            throw new BusinessException("道路运输从业资格证OCR识别失败");
        }
        map.put("name", getWord(res, "姓名"));
        map.put("address", getWord(res, "住址"));
        map.put("occupationalRequirementsNo", getWord(res, "证号"));
        map.put("qualificationCategories", getWord(res, "从业资格证类别"));
        String endDate = getWord(res, "有效期限");
        map.put("qualificationEndDate", DateTimeUtil.stringByZNToDate(endDate));
        return map;
    }

    //道路运输经营许可证 【82836802c85e79c23c6c8b7ee7cab2fb】正本
    @Override
    public Map<String, Object> ocrTransBusinessLicense(Account loginUser, String imagePath) {
        HashMap<String, String> options = new HashMap<>();
        options.put("templateSign", "82836802c85e79c23c6c8b7ee7cab2fb");
        JSONObject res = getAipOcr().custom(imagePath, options);
        Map<String, Object> map = new HashMap<>();
        if (!res.has("data") || !res.getJSONObject("data").has("ret")) {
            throw new BusinessException("道路运输经营许可证ORC识别失败");
        }
        map.put("companyName", getWord(res, "业户姓名"));
        map.put("licenseNo", getWord(res, "许可证编号"));
        map.put("address", getWord(res, "地址"));
        map.put("licenseScope", getWord(res, "经营范围"));
        String endDate = getWord(res, "有效期限");
        map.put("transBusinessLicenseEndDate", DateTimeUtil.stringByZNToDate(endDate));
        return map;
    }

    //行驶证
    @Override
    public Map<String, Object> ocrVehicleLicense(Account loginUser, String imagePath, Side side) {
        if (side == null) {
            side = Side.front;//front：行驶证正面
        }
        HashMap<String, String> options = new HashMap<>();
        options.put("detect_direction", "true");
        options.put("detect_risk", "false");
        options.put("vehicle_license_side", side.name());
        options.put("unified", "true");
//        HatchBaiduOcr ocr = getBaiduOcrByPlat(loginUser);
        JSONObject res = getAipOcr().vehicleLicense(imagePath, options);
        if (!res.has("words_result")) throw new BusinessException("行驶证OCR识别失败,请手动填写证件信息!");
        JSONObject result = res.getJSONObject("words_result");
        Map<String, Object> map = new HashMap<>();
        if (result.has("号牌号码")) {
            map.put("trackNo", result.getJSONObject("号牌号码").getString("words"));
        }
//        if (result.has("车辆类型")) {
//            String truckTypeName = result.getJSONObject("车辆类型").getString("words");
//            if (StringUtil.isNotEmpty(truckTypeName)) {
//                List<TruckType> truckType = ParamUtil.isSuccess(systemRemote.queryTruckTypeByName(truckTypeName));
//                if (truckType.size() == 1) {
//                    map.put("truckTypeName", truckType.get(0).getName());
//                    map.put("truckTypeCode", truckType.get(0).getCode());
//                    map.put("truckTypeId", truckType.get(0).getId());
//                } else {
//                    throw new BusinessException("不支持的车辆类型：" + truckTypeName);
//                }
//            }
//        }
        if (result.has("所有人")) {
            map.put("owner", result.getJSONObject("所有人").getString("words"));
        }
        if (result.has("住址")) {
            map.put("address", result.getJSONObject("住址").getString("words"));
        }
        if (result.has("使用性质")) {
            map.put("usageCharacteristics", result.getJSONObject("使用性质").getString("words"));
        }
        if (result.has("发动机号码")) {
            map.put("engineNo", result.getJSONObject("发动机号码").getString("words"));
        }
        if (result.has("发证单位")) {
            map.put("issuingOrganizations", result.getJSONObject("发证单位").getString("words"));
        }
        if (result.has("车辆识别代号")) {
            map.put("vehicleIdentifyCode", result.getJSONObject("车辆识别代号").getString("words"));
        }
        if (result.has("品牌型号")) {
            map.put("brand", result.getJSONObject("品牌型号").getString("words"));
        }
        if (result.has("注册日期")) {
            String endDate = result.getJSONObject("注册日期").getString("words");
            String year = endDate.substring(0, 4);
            String month = endDate.substring(4, 6);
            String day = endDate.substring(6, 8);
            map.put("registerDate", year + "-" + month + "-" + day);
        }
        if (result.has("发证日期")) {
            String endDate = result.getJSONObject("发证日期").getString("words");
            String year = endDate.substring(0, 4);
            String month = endDate.substring(4, 6);
            String day = endDate.substring(6, 8);
            map.put("issueDate", year + "-" + month + "-" + day);
        }

        if (result.has("外廓尺寸")) {
            String kgStr = result.getJSONObject("外廓尺寸").getString("words");
            if (kgStr.contains("mm")) {
                String kgNumStr = kgStr.split("mm")[0];
                String[] split = kgNumStr.split("X");
                double vehicleLong = Double.parseDouble(split[0]) / 1000;
                double vehicleWidth = Double.parseDouble(split[1]) / 1000;
                double vehicleHeight = Double.parseDouble(split[2]) / 1000;
                map.put("vehicleLong", vehicleLong);
                map.put("vehicleWidth", vehicleWidth);
                map.put("vehicleHeight", vehicleHeight);
            }
        }
        //---
        if (result.has("燃油类型")) {
            String truckEnergyTypeName = result.getJSONObject("燃油类型").getString("words");
            if (StringUtil.isNotEmpty(truckEnergyTypeName)) {
                TruckEnergyType truckEnergyType = paramService.queryTruckEnergyTypeByName(truckEnergyTypeName);
                if (truckEnergyType != null) {
                    map.put("truckEnergyTypeName", truckEnergyType.getName());
                    map.put("truckEnergyTypeCode", truckEnergyType.getCode());
                    map.put("truckEnergyTypeId", truckEnergyType.getId());
                }
            }
        }
        if (result.has("总质量")) {
            String kgStr = result.getJSONObject("总质量").getString("words");
            if (kgStr.contains("kg")) {
                String kgNum = kgStr.split("kg")[0];
                double tw = Double.parseDouble(kgNum) / 1000;
                map.put("vehicleWeight", tw);
            }
        }
        if (result.has("核定载质量")) {
            String kgStr = result.getJSONObject("核定载质量").getString("words");
            if (kgStr.contains("kg")) {
                String kgNum = kgStr.split("kg")[0];
                double tw = Double.parseDouble(kgNum) / 1000;
                map.put("loadingWeight", tw);
            }
        }
        if (result.has("整备质量")) {
            String kgStr = result.getJSONObject("整备质量").getString("words");
            if (kgStr.contains("kg")) {
                String kgNum = kgStr.split("kg")[0];
                double tw = Double.parseDouble(kgNum) / 1000;
                map.put("curbWeight", tw);
            }
        }
        if (result.has("准牵引总质量")) {
            String kgStr = result.getJSONObject("准牵引总质量").getString("words");
            if (kgStr.contains("kg")) {
                String kgNum = kgStr.split("kg")[0];
                double tw = Double.parseDouble(kgNum) / 1000;
                map.put("tractionWeight", tw);
            }
        }
        //如果是牵引车，可能不存在核载质量 将牵引质量赋值
        if (map.get("loadingWeight") == null && map.get("tractionWeight") != null) {
            map.put("loadingWeight", map.get("tractionWeight"));
        }
        //如果是牵引车，可能不存在总质量，总质量=车头+车挂准牵引总质量
        if (map.get("vehicleWeight") == null && map.get("tractionWeight") != null && map.get("curbWeight") != null) {
            map.put("vehicleWeight", ((double) map.get("tractionWeight")) + (double) map.get("curbWeight"));
        }
        return map;
    }

    //道路运输证 【c43789916693c9e19f4ae4106f4051ed】
    @Override
    public Map<String, Object> ocrTransportLicense(Account loginUser, String imagePath) {
        //监测待理证
        HashMap<String, String> options = new HashMap<>();
        options.put("templateSign", "c43789916693c9e19f4ae4106f4051ed");
        JSONObject res = getAipOcr().custom(imagePath, options);
        Map<String, Object> map = new HashMap<>();
        if (!res.has("data") || !res.getJSONObject("data").has("ret")) {
            throw new BusinessException("道路运输证OCR识别失败,请手动填写证件信息!");
        }
        //分割车牌号和颜色
        String vc = getWord(res, "车牌号及颜色");
        if (vc.length() >= 7 && CommonUtil.checkCarNumber(vc.substring(0, 7))) {
            map.put("trackNo", vc.substring(0, 7));
        }
        if (vc.length() > 7) {
            String cName;
            if (vc.contains("(") && vc.contains(")")) {
                cName = vc.substring(vc.indexOf("(") + 1, vc.indexOf(")"));
            } else {
                cName = vc.substring(vc.length() - 2);
            }
            if (cName.contains("色")) cName = cName.replace("色", "牌");
            TruckPlate truckPlate = paramService.queryTruckPlateByName(cName);
            if (truckPlate != null) {
                map.put("truckPlateId", truckPlate.getId());
                map.put("truckPlateName", truckPlate.getName());
            }
        }
        map.put("transLicenseNo", getWord(res, "运输证号"));
        map.put("transBusinessNo", getWord(res, "经营许可证号"));
        map.put("transLicenseName", getWord(res, "业户名称"));
        map.put("address", getWord(res, "地址"));
        map.put("etc", getWord(res, "ETC"));
        map.put("trackTypeName", getWord(res, "车辆类型"));
        map.put("expirationDate", getWord(res, "有效期"));
        return map;
    }

    public String getWord(JSONObject res, String wordName) {
        if (!res.has("data") || !res.getJSONObject("data").has("ret")) {
            return null;
        }
        JSONArray jsonArray = res.getJSONObject("data").getJSONArray("ret");
        for (Object object : jsonArray.toList()) {
            if (((Map) object).get("word_name").equals(wordName)) {
                return (String) ((Map) object).get("word");
            }
        }
        return null;
    }

}

